package com.triones.api.service.third;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.io.IoUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.ruoyi.common.config.LeptageConfig;
import com.ruoyi.common.config.PhotonPayConfig;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.LeptageApiSignUtils;
import com.ruoyi.common.utils.PhpApiSignUtils;
import com.ruoyi.common.utils.SnowflakeIdWorker;
import com.triones.api.entity.*;
import com.triones.api.entity.bo.TransferRequestBodyBO;
import com.triones.api.mapper.*;
import com.triones.api.service.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.BufferedReader;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 第三方业务
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class ApiThirdCallbackServiceImpl implements ApiThirdCallbackService {

    private final BankCardTxnMapper bankCardTxnMapper;

    private final PhotonPayConfig photonPayConfig;

    private final BankCardMapper bankCardMapper;

    private final LeptageConfig leptageConfig;

    private final CryptoInCommonUseAddressMapper cryptoInCommonUseAddressMapper;

    private final CryptoBillMapper cryptoBillMapper;

    private final CryptoBillDetailMapper cryptoBillDetailMapper;

    private final MemberMapper memberMapper;

    private final NoticeService noticeService;

    private final CryptoWalletMapper cryptoWalletMapper;

    private final GlobalAccountEntryMapper globalAccountEntryMapper;

    private final CryptoWalletService cryptoWalletService;

    private final FaitWalletService faitWalletService;

    private final GlobalAccountService globalAccountService;

    private final FeeThaliMapper feeThaliMapper;

    /**
     * php 成功接收回调的通知返回值
     * {"roger": true}
     */
    @Override
    public ResponseEntity<Map<String, Boolean>> phpCardTrade(HttpServletRequest request) {
        Map<String, Boolean> result = new HashMap<>();
        result.put("roger", false);
        try {
            String notificationCatagory = request.getHeader("X-PD-NOTIFICATION-CATAGORY");
            if (notificationCatagory == null || "".equals(notificationCatagory)) {
                return ResponseEntity.ok(result);
            }
            String notificationType = request.getHeader("X-PD-NOTIFICATION-TYPE");
            if (notificationType == null || "".equals(notificationType)) {
                return ResponseEntity.ok(result);
            }
            String notificationSign = request.getHeader("X-PD-SIGN");
            String jsonParam;
            try (BufferedReader reader = request.getReader()) {
                jsonParam = IoUtil.read(reader);
            }
            log.info("php 通知主类 = " + notificationCatagory);
            log.info("php 通知子类 = " + notificationType);
            log.info("php 通知验签 = " + notificationSign);
            log.info("php jsonParam = " + jsonParam);
            if (jsonParam == null || "".equals(jsonParam)) {
                return ResponseEntity.ok(result);
            }
            /**
             * 验签
             */
            if (PhpApiSignUtils.verify(jsonParam, photonPayConfig.getPhotonPayPublicKey(), notificationSign)) {
                result.put("roger", true);
                switch (notificationCatagory) {
                    //发卡交易通知
                    case "issuing":
                        this.saveBankCardTxn(jsonParam, notificationType);
                        break;
                    // 发卡交易结算通知
                    case "issuing_settlement":
                        this.updateBankCardTxn(jsonParam, notificationType);
                        break;
                    // 卡状态通知
                    case "issuing_card":
                        switch (notificationType) {
                            // 卡状态更新通知
                            case "card_status_update":
                                this.cardStatusUpdate(jsonParam);
                        }
                        break;
                    // 全球账户
                    case "GlobalAccount":
                        switch (notificationType) {
                            case "settle":
                                this.updateGlobalAccountEntry(jsonParam);
                        }
                }
            }
            log.info("php 返回通知结果 = " + result);
            return ResponseEntity.ok(result);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException(e.getMessage());
        }
    }

    @Override
    public ResponseEntity<Map<String, Object>> lptEventNotification(HttpServletRequest request) {
        Map<String, Object> result = new HashMap<>();
        result.put("msg", "success");
        result.put("code", "0000");
        try {
            String signature = request.getHeader("X-HOOK-SIGNATURE");
            String nonce = request.getHeader("X-HOOK-NONCE");
            StringBuilder jsonBuilder = new StringBuilder();
            try (BufferedReader reader = request.getReader()) {
                String line;
                while ((line = reader.readLine()) != null) {
                    jsonBuilder.append(line);
                }
            }
            String requestBodyJsonStr = jsonBuilder.toString();
            log.info("lpt 事件回调通知签名 = " + signature);
            log.info("lpt 事件回调通知时间戳 = " + nonce);
            log.info("lpt 事件回调通知请求数据字符串 = " + requestBodyJsonStr);
            if (LeptageApiSignUtils.verifySignatures(Convert.toLong(nonce), leptageConfig.getTrade(), requestBodyJsonStr, signature, leptageConfig.getWebhooksecret())) {
                Map map = JSON.parseObject(requestBodyJsonStr, Map.class);
                if (map != null) {
                    String type = Convert.toStr(map.get("type"));
                    log.info("lpt 事件回调通知类型 = " + type);
                    switch (type) {
                        //充值
                        case "DEPOSIT_TXN":
                            this.updateCryptoBillByCryptoToCrypto(Convert.toStr(map.get("data")));
                            break;
                        //提现、提币
                        case "WITHDRAW_TXN":
                            this.updateCryptoBillByCryptoToFait(Convert.toStr(map.get("data")));
                            break;
                        //新增提币地址
                        case "WITHDRAW_ADDR":
                            this.updateUseAddress(Convert.toStr(map.get("data")));
                            break;
                        default:
                            return ResponseEntity.ok(result);
                    }
                }
            }
            log.info("lpt 事件回调通知返回结果 = " + result);
            return ResponseEntity.ok(result);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ServiceException(e.getMessage());
        }
    }

    @Override
    public ResponseEntity<Map<String, Object>> lptTradeConfirmNotification(HttpServletRequest request) {
        Map<String, Object> result = new HashMap<>();
        result.put("confirmResult", false);
        result.put("msg", "没有权限！！！");
        result.put("code", "ec0001");
        try {
            String signature = request.getHeader("X-HOOK-SIGNATURE");
            String nonce = request.getHeader("X-HOOK-NONCE");
            StringBuilder jsonBuilder = new StringBuilder();
            try (BufferedReader reader = request.getReader()) {
                String line;
                while ((line = reader.readLine()) != null) {
                    jsonBuilder.append(line);
                }
            }
            String requestBodyJsonStr = jsonBuilder.toString();
            log.info("lpt 交易确认回调通知签名 = " + signature);
            log.info("lpt 交易确认回调通知时间戳 = " + nonce);
            log.info("lpt 交易确认回调通知去请求数据字符串 = " + requestBodyJsonStr);
            if (LeptageApiSignUtils.verifySignatures(Convert.toLong(nonce), leptageConfig.getConfirmTrade(), requestBodyJsonStr, signature, leptageConfig.getWebhooksecret())) {
                result.put("msg", "success");
                result.put("code", "0000");
                result.put("confirmResult", true);
                Map map = JSON.parseObject(requestBodyJsonStr, Map.class);
                List<String> ccyList = Arrays.asList("USD");
                if (map != null) {
                    Map data = JSON.parseObject(Convert.toStr(map.get("data")), Map.class);
                    if (data != null) {
                        Map payoutMoney = (Map) data.get("payoutMoney");
                        if (payoutMoney != null) {
                            String ccy = Convert.toStr(payoutMoney.get("ccy"));
                            if (!ccyList.contains(ccy)) {
                                /**
                                 * 提币
                                 */
                                CryptoBillDO cryptoBillDO = cryptoBillMapper.selectOne(new LambdaQueryWrapper<CryptoBillDO>()
                                    .eq(CryptoBillDO::getRequestId, Convert.toStr(data.get("requestId"))));
                                if (cryptoBillDO != null) {
                                    CryptoWalletDO cryptoWalletDO = cryptoWalletMapper.selectOne(new LambdaQueryWrapper<CryptoWalletDO>()
                                        .eq(CryptoWalletDO::getUid, cryptoBillDO.getUid())
                                        .eq(CryptoWalletDO::getCcy, cryptoBillDO.getTransferCcy())
                                        .eq(CryptoWalletDO::getChain, cryptoBillDO.getTransferChain())
                                        .last("limit 1"));
                                    //交易金额
                                    BigDecimal tradeAmount = Convert.toBigDecimal(cryptoBillDO.getSellAmount()).setScale(6, RoundingMode.HALF_UP);
                                    //账户余额
                                    BigDecimal cryptoWalletBalance = Convert.toBigDecimal(cryptoWalletDO.getAmount()).setScale(6, RoundingMode.HALF_UP);
                                    // 账户新的额度
                                    BigDecimal newCryptoWalletBalance = cryptoWalletBalance.subtract(tradeAmount).setScale(6, RoundingMode.HALF_UP);
                                    cryptoWalletDO.setAmount(newCryptoWalletBalance);
                                    cryptoWalletDO.setUpdateTime(System.currentTimeMillis());
                                    cryptoWalletMapper.updateById(cryptoWalletDO);
                                    // 更新账单记录
                                    cryptoBillDO.setStatus(Convert.toStr(data.get("status")));
                                    cryptoBillDO.setTxnId(Convert.toStr(data.get("txnId")));
                                    cryptoBillDO.setSettledAt(System.currentTimeMillis());
                                    cryptoBillDO.setCompletedAt(Convert.toStr(data.get("completedAt")));
                                    cryptoBillMapper.updateById(cryptoBillDO);
                                } else {
                                    result.put("msg", "没有查询到提币交易记录");
                                    result.put("code", "ec0020");
                                }
                            } else {
                                /**
                                 * 提现
                                 */
                                CryptoSysBillDO sysBillDO = cryptoBillDetailMapper.selectOne(new LambdaQueryWrapper<CryptoSysBillDO>()
                                    .eq(CryptoSysBillDO::getRequestId, Convert.toStr(data.get("requestId"))));
                                if (sysBillDO != null) {
                                    Map fee = (Map) data.get("fee");
                                    if (fee != null) {
                                        sysBillDO.setFeeChargeType(Convert.toStr(fee.get("chargeType")));
                                        Map feeMoney = (Map) fee.get("money");
                                        if (feeMoney != null) {
                                            sysBillDO.setFeeMoneyCcy(Convert.toStr(feeMoney.get("ccy")));
                                            sysBillDO.setFeeMoneyAmount(Convert.toBigDecimal(feeMoney.get("ccy")));
                                        }
                                    }
                                    sysBillDO.setTxnId(Convert.toStr(data.get("txnId")));
                                    sysBillDO.setAccountId(Convert.toStr(data.get("accountId")));
                                    sysBillDO.setStatus(Convert.toStr(data.get("status")));
                                    sysBillDO.setPayoutMoneyAmount(Convert.toBigDecimal(payoutMoney.get("amount")));
                                    sysBillDO.setFailedCode(Convert.toStr(data.get("failedCode")));
                                    sysBillDO.setFailedReason(Convert.toStr(data.get("failedReason")));
                                    sysBillDO.setReturnFee(Convert.toStr(data.get("returnFee")));
                                    sysBillDO.setCreatedAt(Convert.toStr(data.get("createdAt")));
                                    cryptoBillDetailMapper.updateById(sysBillDO);
                                } else {
                                    result.put("msg", "没有查询到交易记录");
                                    result.put("code", "ec0020");
                                }
                            }
                        } else {
                            result.put("msg", "请求体数据异常");
                            result.put("code", "ec0010");
                        }
                    } else {
                        result.put("msg", "请求体数据异常");
                        result.put("code", "ec0010");
                    }
                }
            } else {
                result.put("msg", "请求体数据异常");
                result.put("code", "ec0010");
            }
            return ResponseEntity.ok(result);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("e = " + e);
            throw new ServiceException(e.getMessage());
        }
    }

    /**
     * 保存银行卡交易明细
     */
    public void saveBankCardTxn(String requestBodyJsonStr, String notificationType) {
        Map map = JSON.parseObject(requestBodyJsonStr, Map.class);
        switch (notificationType) {
            case "auth":
                if (map != null) {
                    BankCardDO bankCardDO = bankCardMapper.selectOne(new LambdaQueryWrapper<BankCardDO>()
                        .eq(BankCardDO::getCardId, Convert.toStr(map.get("cardId"))));
                    if (bankCardDO != null) {
                        BankCardTxnDO bankCardTxn = bankCardTxnMapper.selectOne(new LambdaQueryWrapper<BankCardTxnDO>()
                            .eq(BankCardTxnDO::getTransactionId, Convert.toStr(map.get("transactionId"))));
                        if (bankCardTxn == null) {
                            bankCardTxn = new BankCardTxnDO();
                            bankCardTxn.setUid(bankCardDO.getUid());
                            bankCardTxn.setCardNo(bankCardDO.getCardNo());
                            bankCardTxn.setCreateAt(Convert.toStr(map.get("createdAt")));
                            bankCardTxn.setMemberId(Convert.toStr(map.get("memberId")));
                            bankCardTxn.setMatrixAccount(Convert.toStr(map.get("matrixAccount")));
                            bankCardTxn.setUpdatedAt(Convert.toStr(map.get("updatedAt")));
                            bankCardTxn.setTransactionId(Convert.toStr(map.get("transactionId")));
                            bankCardTxn.setOriginTransactionId(Convert.toStr(map.get("originTransactionId")));
                            bankCardTxn.setTransactionType(Convert.toStr(map.get("transactionType")));
                            bankCardTxn.setCardId(Convert.toStr(map.get("cardId")));
                            bankCardTxn.setRequestId(Convert.toStr(map.get("requestId")));
                            bankCardTxn.setTransactionAmount(Convert.toStr(map.get("transactionAmount")));
                            bankCardTxn.setTransactionCurrency(Convert.toStr(map.get("transactionCurrency")));
                            bankCardTxn.setStatus(Convert.toStr(map.get("status")));
                            bankCardTxn.setMerchantNameLocation(Convert.toStr(map.get("merchantNameLocation")));
                            bankCardTxn.setMerchantLocation(Convert.toStr(map.get("merchantLocation")));
                            bankCardTxn.setCode(Convert.toStr(map.get("code")));
                            bankCardTxn.setMsg(Convert.toStr(map.get("msg")));
                            bankCardTxn.setAuthCode(Convert.toStr(map.get("authCode")));
                            bankCardTxn.setCardType(Convert.toStr(map.get("cardType")));
                            bankCardTxn.setAvailableTransactionLimit(Convert.toStr(map.get("availableTransactionLimit")));
                            bankCardTxn.setTxnPrincipalChangeAccount(Convert.toStr(map.get("txnPrincipalChangeAccount")));
                            bankCardTxn.setTxnPrincipalChangeCurrency(Convert.toStr(map.get("txnPrincipalChangeCurrency")));
                            bankCardTxn.setTxnPrincipalChangeAmount(Convert.toStr(map.get("txnPrincipalChangeAmount")));
                            bankCardTxn.setFeeDeductionAccount(Convert.toStr(map.get("feeDeductionAccount")));
                            bankCardTxn.setFeeDeductionCurrency(Convert.toStr(map.get("feeDeductionCurrency")));
                            bankCardTxn.setFeeDeductionAmount(Convert.toStr(map.get("feeDeductionAmount")));
                            bankCardTxn.setFeeReturnAccount(Convert.toStr(map.get("feeReturnAccount")));
                            bankCardTxn.setFeeReturnCurrency(Convert.toStr(map.get("feeReturnCurrency")));
                            bankCardTxn.setFeeReturnAmount(Convert.toStr(map.get("feeReturnAmount")));
                            bankCardTxn.setFeeDetailJson(Convert.toStr(map.get("feeDetailJson")));
                            bankCardTxn.setFeeReturnDetailJson(Convert.toStr(map.get("feeReturnDetailJson")));
                            bankCardTxn.setArrivalAccount(Convert.toStr(map.get("arrivalAccount")));
                            bankCardTxn.setArrivalAmount(Convert.toStr(map.get("arrivalAmount")));
                            bankCardTxn.setSettleStatus("pending");
                            /**
                             * 处理消费手续费收取
                             */
                            FeeThaliDO appleAuth = feeThaliMapper.selectOne(new LambdaQueryWrapper<FeeThaliDO>().eq(FeeThaliDO::getType, "auth")
                                .eq(FeeThaliDO::getSubType, "APPLEPAY")
                                .last("limit 1"));

                            FeeThaliDO otherAuth = feeThaliMapper.selectOne(new LambdaQueryWrapper<FeeThaliDO>().eq(FeeThaliDO::getType, "auth")
                                .eq(FeeThaliDO::getSubType, "OTHER")
                                .last("limit 1"));

                            // 支付类型
                            String merchantNameLocation = Convert.toStr(map.get("merchantNameLocation"), "");
                            String payType = merchantNameLocation.split("\\*")[0];
                            // 变动的本金
                            BigDecimal txnPrincipalChangeAmount = Convert.toBigDecimal(map.get("txnPrincipalChangeAmount"), BigDecimal.ZERO).abs();
                            if (otherAuth != null) {
                                List<Map<String, String>> feeConfigList = JSON.parseObject(otherAuth.getFeeConfig(), List.class);
                                BigDecimal smallAmountMin = Convert.toBigDecimal(feeConfigList.get(0).get("min"));
                                BigDecimal smallAmountMax = Convert.toBigDecimal(feeConfigList.get(0).get("max"));
                                if (txnPrincipalChangeAmount.compareTo(smallAmountMin) >= 0 && txnPrincipalChangeAmount.compareTo(smallAmountMax) <= 0) {
                                    // 小额支付
                                    bankCardTxn.setSysFeeDeductionCurrency(Convert.toStr(map.get("feeDeductionCurrency")));
                                    bankCardTxn.setSysFeeDeductionAccount(Convert.toBigDecimal(feeConfigList.get(0).get("ratio")).negate());
                                } else {
                                    // 大额支付
                                    bankCardTxn.setSysFeeDeductionCurrency(Convert.toStr(map.get("feeDeductionCurrency")));
                                    bankCardTxn.setSysFeeDeductionAccount(txnPrincipalChangeAmount.multiply(Convert.toBigDecimal(feeConfigList.get(1).get("ratio")).divide(BigDecimal.valueOf(100))).setScale(2, RoundingMode.DOWN).negate());
                                }
                            }
                            /**
                             * 更新钱包和全球账户累计金额
                             */
                            BigDecimal feeDeductionAmount = bankCardTxn.getSysFeeDeductionAccount().abs();
                            faitWalletService.fiatWalletCardUpdate(bankCardDO.getUid(), "USD", txnPrincipalChangeAmount.add(feeDeductionAmount), "decrease", Convert.toStr(map.get("cardId")));
                            globalAccountService.updateCumulativeAmount(txnPrincipalChangeAmount.add(feeDeductionAmount));
                            bankCardTxnMapper.insert(bankCardTxn);
                        } else {
                            bankCardTxn.setStatus(Convert.toStr(map.get("status")));
                            bankCardTxnMapper.updateById(bankCardTxn);
                        }
                    }
                    break;
                }
            default:
        }
    }

    /**
     * 充值
     */
    private void updateCryptoBillByCryptoToCrypto(String data) {
        Map mapRequestBody = JSON.parseObject(data, Map.class);
        if (mapRequestBody != null) {
            BigDecimal amount = Convert.toBigDecimal(mapRequestBody.get("amount"));
            Map chainInfo = JSON.parseObject(Convert.toStr(mapRequestBody.get("chainInfo")), Map.class);
            if (chainInfo != null) {
                CryptoWalletDO cryptoWalletDO = cryptoWalletMapper.selectOne(new LambdaQueryWrapper<CryptoWalletDO>()
                    .eq(CryptoWalletDO::getCcy, Convert.toStr(mapRequestBody.get("ccy")))
                    .eq(CryptoWalletDO::getAddress, Convert.toStr(chainInfo.get("destinationAddress")))
                    .eq(CryptoWalletDO::getChain, Convert.toStr(chainInfo.get("chain"))));
                if (cryptoWalletDO != null) {
                    // 获取接受用户账号信息
                    MemberDO memberDO = memberMapper.selectById(cryptoWalletDO.getUid());
                    if (memberDO != null) {
                        String requestIdStr = Convert.toStr(SnowflakeIdWorker.generateUniqueId());
                        CryptoBillDO cryptoBillDO = new CryptoBillDO();
                        cryptoBillDO.setUid(memberDO.getId());
                        cryptoBillDO.setRequestId(requestIdStr);
                        cryptoBillDO.setTransferCcy(Convert.toStr(mapRequestBody.get("ccy")));
                        cryptoBillDO.setTargetCcy(Convert.toStr(mapRequestBody.get("ccy")));
                        cryptoBillDO.setBuyAmount(amount);
                        cryptoBillDO.setScene("transfer-in");
                        cryptoBillDO.setStatus(Convert.toStr(mapRequestBody.get("status")));
                        cryptoBillDO.setCreateTime(Convert.toLong(mapRequestBody.get("createdAt")));
                        cryptoBillDO.setSettledAt(Convert.toLong(mapRequestBody.get("createdAt")));
                        cryptoBillDO.setTxnId(Convert.toStr(mapRequestBody.get("txnId")));
                        cryptoBillDO.setCompletedAt(Convert.toStr(mapRequestBody.get("createdAt")));
                        cryptoBillDO.setTransferAccount(Convert.toStr(chainInfo.get("sourceAddress")));
                        cryptoBillDO.setTargetAccount(Convert.toStr(chainInfo.get("destinationAddress")));
                        cryptoBillDO.setTxnHash(Convert.toStr(chainInfo.get("txnHash")));
                        cryptoBillDO.setTransferChain(Convert.toStr(chainInfo.get("chain")));
                        cryptoBillDO.setTargetChain(Convert.toStr(chainInfo.get("chain")));
                        cryptoBillMapper.insert(cryptoBillDO);
                        /**
                         * 查询用户的crypto钱包地址
                         */
                        if ("SUCCEEDED".equals(Convert.toStr(mapRequestBody.get("status")))) {
                            // 划转
                            TransferRequestBodyBO bodyBO = new TransferRequestBodyBO();
                            bodyBO.setCcy(Convert.toStr(mapRequestBody.get("ccy")));
                            bodyBO.setChain(Convert.toStr(chainInfo.get("chain")));
                            bodyBO.setAmount(Convert.toStr(amount));
                            cryptoWalletService.transfer(bodyBO, "OUT", cryptoBillDO.getUid());
                            // 给用户对应crypto钱包上账
                            cryptoWalletDO.setAmount(cryptoWalletDO.getAmount().add(amount));
                            cryptoWalletDO.setUpdateTime(System.currentTimeMillis());
                            cryptoWalletMapper.updateById(cryptoWalletDO);
                            // 发送通知
                            String mailContent = "Crypto入金通知";
                            String subContent = "您有一笔入金，请查收。";
                            noticeService.addNotice(1911687510910357507L, mailContent, subContent, memberDO.getId());
                        }
                    }
                }
            }
        }
    }

    /**
     * 根据回调信息修改子钱包提现交易、提币交易
     */
    private void updateCryptoBillByCryptoToFait(String data) {
        List<String> ccyList = Arrays.asList("USD");
        Map mapRequestBody = JSON.parseObject(data, Map.class);
        if (mapRequestBody != null) {
            CryptoBillDO cryptoBillDO = cryptoBillMapper.selectOne(new LambdaQueryWrapper<CryptoBillDO>().eq(CryptoBillDO::getTxnId, Convert.toStr(mapRequestBody.get("txnId"))));
            if (cryptoBillDO != null) {
                String status = Convert.toStr(mapRequestBody.get("status"));
                Map payoutMoney = JSON.parseObject(Convert.toStr(mapRequestBody.get("payoutMoney")), Map.class);
                if (!ccyList.contains(Convert.toStr(payoutMoney.get("ccy")))) {
                    /**
                     * 提币操作
                     */
                    // 更新状态
                    cryptoBillDO.setStatus(status);
                    cryptoBillDO.setSettledAt(System.currentTimeMillis());
                    cryptoBillDO.setCompletedAt(Convert.toStr(mapRequestBody.get("completedAt")));
                    cryptoBillMapper.updateById(cryptoBillDO);
                    if ("SUCCEEDED".equals(status)) {
                        // 通知
                        String mailContent = "Crypto提币通知";
                        String subContent = "您有一笔Crypto提币交易成功。";
                        noticeService.addNotice(1911687396712042497L, mailContent, subContent, cryptoBillDO.getUid());
                    } else if ("FAILED".equals(status)) {
                        // 通知
                        String mailContent = "Crypto提币通知";
                        String subContent = "您有一笔Crypto提币交易失败。";
                        noticeService.addNotice(1911687396712042497L, mailContent, subContent, cryptoBillDO.getUid());

                        //划转
                        TransferRequestBodyBO bodyBO = new TransferRequestBodyBO();
                        bodyBO.setCcy(cryptoBillDO.getTransferCcy());
                        bodyBO.setChain(cryptoBillDO.getTargetChain());
                        bodyBO.setAmount(Convert.toStr(cryptoBillDO.getBuyAmount().add(cryptoBillDO.getRate())));
                        cryptoWalletService.transfer(bodyBO, "OUT", cryptoBillDO.getUid());

                        // 查询加密货币钱包
                        CryptoWalletDO cryptoWalletDO = cryptoWalletMapper.selectOne(new LambdaQueryWrapper<CryptoWalletDO>()
                            .eq(CryptoWalletDO::getUid, cryptoBillDO.getUid()).eq(CryptoWalletDO::getCcy, cryptoBillDO.getTransferCcy())
                            .eq(CryptoWalletDO::getChain, cryptoBillDO.getTransferChain()));
                        if (cryptoWalletDO != null) {
                            cryptoWalletDO.setAmount(Convert.toBigDecimal(cryptoWalletDO.getAmount()).add(Convert.toBigDecimal(cryptoBillDO.getSellAmount())));
                            cryptoWalletDO.setUpdateTime(System.currentTimeMillis());
                            cryptoWalletMapper.updateById(cryptoWalletDO);
                        }
                    }
                } else {
                    /**
                     * 提现操作
                     */
                    CryptoSysBillDO cryptoBillDetailDO = cryptoBillDetailMapper.selectOne(new LambdaQueryWrapper<CryptoSysBillDO>()
                        .eq(CryptoSysBillDO::getTxnId, Convert.toStr(mapRequestBody.get("txnId"))));
                    if ("SUCCEEDED".equals(status)) {
                        if (cryptoBillDetailDO != null) {
                            cryptoBillDetailDO.setStatus(status);
                            cryptoBillDetailDO.setSettledAt(Convert.toStr(System.currentTimeMillis()));
                            cryptoBillDetailDO.setCompletedAt(Convert.toStr(System.currentTimeMillis()));
                            cryptoBillDetailMapper.updateById(cryptoBillDetailDO);
                        }
                    }
                }
            }
        }
    }

    /**
     * 根据回调信息修改提币地址状态
     */
    public void updateUseAddress(String data) {
        Map mapRequestBody = JSON.parseObject(data, Map.class);
        if (mapRequestBody != null) {
            CryptoInCommonUseAddressDO cryptoInCommonUseAddressDO = cryptoInCommonUseAddressMapper
                .selectOne(new LambdaQueryWrapper<CryptoInCommonUseAddressDO>().eq(CryptoInCommonUseAddressDO::getBeneId, Convert.toStr(mapRequestBody.get("beneId"))));
            if (cryptoInCommonUseAddressDO != null) {
                cryptoInCommonUseAddressDO.setStatus(Convert.toStr(mapRequestBody.get("status")));
                cryptoInCommonUseAddressMapper.updateById(cryptoInCommonUseAddressDO);
            }
        }
    }

    /**
     * 卡状态更新
     */
    public void cardStatusUpdate(String data) {
        Map mapRequestBody = JSON.parseObject(data, Map.class);
        if (mapRequestBody != null) {
            BankCardDO bankCardDO = bankCardMapper.selectOne(new LambdaQueryWrapper<BankCardDO>().eq(BankCardDO::getCardId, mapRequestBody.get("cardId")));
            if (bankCardDO != null) {
                bankCardDO.setCardNumber(Convert.toStr(mapRequestBody.get("cardNumber")));
                bankCardDO.setCardholderId(Convert.toStr(mapRequestBody.get("cardholderId")));
                bankCardDO.setCardStatus(Convert.toStr(mapRequestBody.get("cardStatus")));
                bankCardDO.setProduceStatus(Convert.toStr(mapRequestBody.get("produceStatus")));
                bankCardDO.setTrackingNumber(Convert.toStr(mapRequestBody.get("trackingNumber")));
                bankCardDO.setUpdatedAt(Convert.toStr(mapRequestBody.get("updatedAt")));
                bankCardMapper.updateById(bankCardDO);
            }
        }
    }

    /**
     * 更新确认申请全球账户
     */
    private void updateGlobalAccountEntry(String data) {
        Map mapRequestBody = JSON.parseObject(data, Map.class);
        if (mapRequestBody != null) {
            GlobalAccountEntryDO globalAccountEntryDO = new GlobalAccountEntryDO();
            globalAccountEntryDO.setMemberId(Convert.toStr(mapRequestBody.get("memberId")));
            globalAccountEntryDO.setCertificationDocumentStatus(Convert.toStr(mapRequestBody.get("certificationDocumentStatus")));
            globalAccountEntryDO.setCreatedAt(Convert.toStr(mapRequestBody.get("createdAt")));
            globalAccountEntryDO.setCreditAmount(Convert.toStr(mapRequestBody.get("creditAmount")));
            globalAccountEntryDO.setCreditCurrency(Convert.toStr(mapRequestBody.get("creditCurrency")));
            globalAccountEntryDO.setDiscountAmount(Convert.toStr(mapRequestBody.get("discountAmount")));
            globalAccountEntryDO.setDiscountCurrency(Convert.toStr(mapRequestBody.get("discountCurrency")));
            globalAccountEntryDO.setFeeAmount(Convert.toStr(mapRequestBody.get("feeAmount")));
            globalAccountEntryDO.setFeeCurrency(Convert.toStr(mapRequestBody.get("feeCurrency")));
            globalAccountEntryDO.setGlobalAccountNo(Convert.toStr(mapRequestBody.get("globalAccountNo")));
            globalAccountEntryDO.setPayerAccount(Convert.toStr(mapRequestBody.get("payerAccount")));
            globalAccountEntryDO.setPayerName(Convert.toStr(mapRequestBody.get("payerName")));
            globalAccountEntryDO.setPaymentReference(Convert.toStr(mapRequestBody.get("paymentReference")));
            globalAccountEntryDO.setSettlementAmount(Convert.toStr(mapRequestBody.get("settlementAmount")));
            globalAccountEntryDO.setSettlementCurrency(Convert.toStr(mapRequestBody.get("settlementCurrency")));
            globalAccountEntryDO.setSettlementNo(Convert.toStr(mapRequestBody.get("settlementNo")));
            globalAccountEntryDO.setSettlementStatus(Convert.toStr(mapRequestBody.get("settlementStatus")));
            globalAccountEntryDO.setSettlementAt(Convert.toStr(mapRequestBody.get("settlementStatus")));
            globalAccountEntryMapper.insert(globalAccountEntryDO);
        }
    }

    /**
     * 更新银行卡交易记录
     *
     * @param requestBodyJsonStr
     * @param notificationType
     */
    public void updateBankCardTxn(String requestBodyJsonStr, String notificationType) {
        Map mapRequestBody = JSON.parseObject(requestBodyJsonStr, Map.class);
        if (mapRequestBody != null) {
            BankCardTxnDO bankCardTxnDO = bankCardTxnMapper.selectOne(new LambdaQueryWrapper<BankCardTxnDO>().eq(BankCardTxnDO::getTransactionId, mapRequestBody.get("transactionId")));
            if (bankCardTxnDO != null) {
                bankCardTxnDO.setTransactionStatus(Convert.toStr(mapRequestBody.get("transactionStatus")));
                bankCardTxnMapper.updateById(bankCardTxnDO);
            }
//            switch (notificationType) {
//                // 消费
//                case "auth":
//                    break;
//                // 退款
//                case "refund":
//                    break;
//                // 充值/汇入
//                case "fund_in":
//                    break;
//                default:
//            }
        }
    }
}
